home *** CD-ROM | disk | FTP | other *** search
- /*
- * uujoin [ -r ] [ {-amiga | -mac | -pc} ] file(s)...
- * join and decode Usenet encoded binary files.
- *
- * Author: Mark R. Rinfret
- * Date: 08-15-90
- *
- * Public Domain - Use as you wish.
- *
- * Notes: The uudecode portion was adapted from uudecode.c, packaged
- * with Matt Dillon's UUCP implementation.
- *
- * The Macintosh mode simply filters and joins the files. It
- * doesn't decode the BinHex format (got a de-binhexer I can
- * have?).
- *
- * The delimiter strings used to extract the encoded segments
- * may change over time. Just edit the assignments to the
- * string variables "start" and "stop", as appropriate.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <FileScan.h>
- #include <functions.h>
-
- extern int unlink(const char *fileName);
-
- extern int errno;
-
- /* single character decode */
- #define DEC(c) (((c) - ' ') & 077)
-
- char *versionString =
- "uujoin 1.01 - join and decode Usenet encoded binary files.";
-
- int decode(FILE *in, FILE *out);
- int outdec(char *p, FILE *f, int n);
- int fr(FILE *fd, char *buf, int cnt);
-
- #define AMI 0
- #define MAC 1
- #define PC 2
-
- int fileCount; /* set by FileScan() */
- char **fileNames; /* allocated by FileScan() */
- int fileNumber; /* index into fileNames */
- char line[256]; /* allows for long Usenet lines */
- int machine; /* machine type */
- int removeFiles = 0; /* 1 => remove originals */
- char tempName[L_tmpnam]; /* temporary file name */
-
- int
- DecodeHexFile(void)
- {
- char newName[128];
- char *s;
- int status = 0;
-
- /* Eventually, the code to de-binhex the file will be placed here.
- * for now, just rename the temp file as <newName>.hex.
- */
-
- /* Use first filename as the base for the new filename. */
- strcpy(newName, fileNames[0]);
- s = strrchr(newName, '.'); /* Find rightmost period. */
- if (s) *s = '\0'; /* Drop current suffix. */
- strcat(newName,".hex"); /* Add ".hex" suffix. */
- if (! Rename(tempName, newName)) { /* Rename the file. */
- status = IoErr();
- fprintf(stderr,"Could not rename '%s' to '%s'; error %ld\n",
- tempName, newName, (LONG) status);
- }
- return status;
- }
-
- int
- DecodeMergedFile(void)
- {
- char dest[128];
-
- FILE *in = NULL, *out = NULL;
- int mode; /* file protection */
-
- in = fopen(tempName, "r");
- if (! in ) {
- fprintf(stderr,"Could not reopen merged file: '%s'\n", tempName);
- exit(1);
- }
-
- /* Search for header line */
- for (;;) {
- if (fgets(line, sizeof line, in) == NULL) {
- fprintf(stderr, "No begin line\n");
- exit(1);
- }
- if (strncmp(line, "begin ", 6) == 0)
- break;
- }
-
- sscanf(line, "begin %o %s", &mode, dest);
-
- /* create output file */
- out = fopen(dest, "w");
- if (out == NULL) {
- perror(dest);
- exit(1);
- }
-
- decode(in, out);
-
- if (fgets(line, sizeof line, in) == NULL || strcmp(line, "end\n")) {
- fprintf(stderr, "No end line\n");
- exit(5);
- }
- fclose(in);
-
- return 0;
- }
-
- int
- JoinFiles(void)
- {
- char *fName; /* current file name */
- FILE *inFile = NULL;
- char *p; /* adjusted line pointer */
- char *start, *stop; /* pattern matching strings */
- int startLeng, stopLeng; /* pattern lengths */
- int status = 0;
- FILE *tempFile = NULL;
-
- tmpnam(tempName);
- tempFile = fopen(tempName, "w");
- if (!tempFile) {
- perror(tempName);
- status = errno;
- goto done;
- }
-
- /* Set up pattern strings according to machine type. Patterns are
- * matched from beginning of line through number of chars in pattern.
- */
-
- if (machine == MAC) {
- start = "---";
- stop = "--- end";
- }
- else if (machine == PC) {
- start = "BEGIN";
- stop = "END--";
- }
- else { /* AMIGA */
- start = "sed";
- stop = "SHAR_EOF";
- }
-
- /* Compute the lengths of the match strings. */
-
- startLeng = strlen(start);
- stopLeng = strlen(stop);
-
- /* The Amiga binaries are packaged as shar files and therefore have a
- * leading 'X' which must be tossed. Other formats (so far) are not
- * packed as shar files and thus, the whole line is used.
- */
- p = (machine == AMI ? (line + 1) : line);
-
- while (fileNumber < fileCount) {
- fName = fileNames[fileNumber]; /* For programming convenience. */
- inFile = fopen(fName, "r");
- if (! inFile) {
- perror(fName);
- status = errno;
- goto done;
- }
-
- /* Attempt to find the start of this file. */
-
- if (startLeng) {
- while (1) {
- fgets(line, sizeof(line), inFile);
- if ( feof(inFile) ) {
- eof_err:
- fprintf(stderr,"uujoin: unexpected EOF in file '%s'!\n", fName);
- status = EOF;
- goto done;
- }
- if (strncmp(start, line, startLeng) == 0)
- break; /* We found the beginning. */
- }
- }
-
- while (1) {
- fgets(line, sizeof(line), inFile);
- if ( feof(inFile) ) {
- if (stopLeng == 0)
- break;
- else
- goto eof_err;
- }
-
- if ( (*line != '\n') && (strncmp(stop, line, stopLeng) == 0) )
- break; /* We found the end. */
-
- if ( fputs(p, tempFile) ) { /* Write the _adjusted_ line. */
- status = EOF;
- fprintf(stderr,"uujoin: error writing to temp file '%s'\n",
- tempName);
- exit(1);
- }
- }
- fclose(inFile);
- ++fileNumber;
- }
-
- done:
- if (tempFile) fclose(tempFile);
- if (inFile) fclose(inFile);
- return status;
- }
-
- main(int argc, char **argv)
- {
-
- if (argc < 2) {
- usage:
- puts(versionString);
- puts("Usage: uujoin [options] file1 [... filen]");
- puts(" where [options] may be:");
- puts("\t-amiga -> uuencoded files wrapped with shar");
- puts("\t-mac -> Macintosh binhex files (not decoded in this release)");
- puts("\t-pc -> uuencoded files enclosed in BEGIN/END pairs");
- puts("\t-r -> remove original files when done");
- puts("\n\tUnix-style wildcards may be used in file specifications.");
- puts("\n\tExample: uujoin -amiga -r program.??");
- puts("\n\tMark R. Rinfret, August 1990.");
- puts("\tContributed to the public domain.");
- exit(1);
- }
-
- --argc; /* Skip over program name. */
- ++argv;
-
- while (**argv == '-') {
- if (strcmp(*argv,"-mac") == 0) {
- machine = MAC;
- bump:
- --argc; /* Skip this arg. */
- ++argv;
- }
- else if (strcmp(*argv, "-pc") == 0) {
- machine = PC;
- goto bump;
- }
- else if (strcmp(*argv,"-amiga") == 0) {
- machine = AMI;
- goto bump;
- }
- else if (strcmp(*argv,"-r") == 0) {
- removeFiles = 1;
- goto bump;
- }
- else
- goto usage;
- }
-
- fileNames = FileScan(argv, argc, &fileCount, 1);
- if (! fileNames) {
- printf("Filename expansion failed - abort!\n");
- exit(1);
- }
-
- if (JoinFiles()) exit(1); /* Attempt to join files. */
-
- if (machine == MAC) {
- if (DecodeHexFile()) exit(1);
- }
- else {
- if (DecodeMergedFile()) exit(1);
- }
-
- unlink(tempName);
- if (removeFiles) {
- while (--fileCount >= 0) {
- unlink(fileNames[fileCount]);
- }
- }
- exit(0);
- }
-
- /*
- * copy from in to out, decoding as you go along.
- */
- decode(in, out)
- FILE *in;
- FILE *out;
- {
- char buf[80];
- char *bp;
- int n;
-
- for (;;) {
- /* for each input line */
- if (fgets(buf, sizeof buf, in) == NULL) {
- printf("Short file\n");
- exit(10);
- }
- n = DEC(buf[0]);
- if (n <= 0)
- break;
-
- bp = &buf[1];
- while (n > 0) {
- outdec(bp, out, n);
- bp += 4;
- n -= 3;
- }
- }
- }
-
- /*
- * output a group of 3 bytes (4 input characters).
- * the input chars are pointed to by p, they are to
- * be output to file f. n is used to tell us not to
- * output all of them at the end of the file.
- */
- outdec(p, f, n)
- char *p;
- FILE *f;
- {
- int c1, c2, c3;
-
- c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
- c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
- c3 = DEC(p[2]) << 6 | DEC(p[3]);
- if (n >= 1)
- fputc(c1, f);
- if (n >= 2)
- fputc(c2, f);
- if (n >= 3)
- fputc(c3, f);
- }
-
-
- /* fr: like read but stdio */
- int
- fr(fd, buf, cnt)
- FILE *fd;
- char *buf;
- int cnt;
- {
- int c, i;
-
- for (i=0; i<cnt; i++) {
- c = fgetc(fd);
- if (c == EOF)
- return(i);
- buf[i] = c;
- }
- return (cnt);
- }
-
-